﻿using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Protocol;
using MQTTnet.Server;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Common
{
  public class MqttClientService
  {
    private static IMqttClient _clinet;
    public MqttClientService()
    {
      Connect();
    }    
    public void Connect()
    {
      string broker = "175.178.25.219";
      int port = 6003;
      string clientId = Guid.NewGuid().ToString();
      //string topic = "csharp/mqtt";
      string username = "tt123";
      string password = "tt123";     

      var options = new MqttClientOptionsBuilder()
          .WithTcpServer(broker, port) // MQTT broker address and port
          .WithCredentials(username, password) // Set username and password
          .WithClientId(clientId)
          .WithCleanSession()
          .Build();

      _clinet = new MqttFactory().CreateMqttClient();
      _clinet.ConnectedAsync += _clinet_ConnectedAsync; // 客户端连接成功事件
      _clinet.DisconnectedAsync += _clinet_DisconnectedAsync; // 客户端连接关闭事件
      _clinet.ApplicationMessageReceivedAsync += _clinet_ApplicationMessageReceivedAsync; // 收到消息事件
      _clinet.ConnectAsync(options);
    }

    /// <summary>
    /// 客户端连接关闭事件
    /// </summary>
    /// <param name="arg"></param>
    /// <returns></returns>
    private Task _clinet_DisconnectedAsync(MqttClientDisconnectedEventArgs arg)
    {
      Console.WriteLine($"客户端已断开与服务端的连接……");
      return Task.CompletedTask;
    }

    /// <summary>
    /// 客户端连接成功事件
    /// </summary>
    /// <param name="arg"></param>
    /// <returns></returns>
    private Task _clinet_ConnectedAsync(MqttClientConnectedEventArgs arg)
    {
      Console.WriteLine($"客户端已连接服务端……");

      // 订阅消息主题
      // MqttQualityOfServiceLevel: （QoS）:  0 最多一次，接收者不确认收到消息，并且消息不被发送者存储和重新发送提供与底层 TCP 协议相同的保证。
      // 1: 保证一条消息至少有一次会传递给接收方。发送方存储消息，直到它从接收方收到确认收到消息的数据包。一条消息可以多次发送或传递。
      // 2: 保证每条消息仅由预期的收件人接收一次。级别2是最安全和最慢的服务质量级别，保证由发送方和接收方之间的至少两个请求/响应（四次握手）。
      _clinet.SubscribeAsync("topic1", MqttQualityOfServiceLevel.AtLeastOnce); //topic_02

      return Task.CompletedTask;
    }

    /// <summary>
    /// 收到消息事件
    /// </summary>
    /// <param name="arg"></param>
    /// <returns></returns>
    private Task _clinet_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg)
    {
      Console.WriteLine($"ApplicationMessageReceivedAsync：客户端ID=【{arg.ClientId}】接收到消息。 Topic主题=【{arg.ApplicationMessage.Topic}】 消息=【{Encoding.UTF8.GetString(arg.ApplicationMessage.PayloadSegment)}】 qos等级=【{arg.ApplicationMessage.QualityOfServiceLevel}】");
      return Task.CompletedTask;
    }

    public void Publish(string topic,string data)
    {
      var message = new MqttApplicationMessage
      {
        Topic = topic,
        PayloadSegment = Encoding.Default.GetBytes(data),
        QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce,
        Retain = false  // 服务端是否保留消息。true为保留，如果有新的订阅者连接，就会立马收到该消息。
      };
      _clinet.PublishAsync(message);
    }
  }
}
